package com.ksana.orm.proxy;

import com.ksana.orm.annotation.Delete;
import com.ksana.orm.annotation.Insert;
import com.ksana.orm.annotation.Select;
import com.ksana.orm.annotation.Update;
import com.ksana.orm.enumerate.MethodEnum;
import com.ksana.orm.session.SqlSession;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Fall
 */
public class MapperProxy implements InvocationHandler {
    private SqlSession sqlsession;

    public MapperProxy(SqlSession sqlsession) {
        this.sqlsession = sqlsession;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 接口使用 invoke 方法 通过自定映射 加载不同的方法
        MethodEnum methodType = type(method);

        if (methodType == null) {
            throw new Exception("无法找到匹配的方法");
        }

        switch (methodType) {
            case SELECT_ONE:
                return sqlsession.selectOne(method, args);
            case SELECT_LIST:
                return sqlsession.selectList(method, args);
            case INSERT:
                return sqlsession.insert(method, args);
            case UPDATE:
                return sqlsession.update(method, args);
            case DELETE:
                return sqlsession.delete(method, args);
        }

        return null;
    }

    /**
     * 方法方法的类型
     *
     * @param method
     * @return
     */
    private MethodEnum type(Method method) {
        // 检测方法类型
        if (method.isAnnotationPresent(Select.class)) {
            String returnType = method.getReturnType().getName();
            // 如果方位的类型是list需要调用
            if (returnType.equals(List.class.getName()) || returnType.equals(ArrayList.class.getName()) ||
                    returnType.equals(LinkedList.class.getName())) {
                return MethodEnum.SELECT_LIST;
            }
            return MethodEnum.SELECT_ONE;
        }

        if (method.isAnnotationPresent(Insert.class)) {
            return MethodEnum.INSERT;
        }

        if (method.isAnnotationPresent(Update.class)) {
            return MethodEnum.UPDATE;
        }

        if (method.isAnnotationPresent(Delete.class)) {
            return MethodEnum.DELETE;
        }

        return null;
    }
}
